/************************************************************
** @brief   : drv_epd_if
** @author  : vandoul
** @github  : https://gitee.com/vandoul
** @date    : 2022-01
** @version : v1.0.0
** @note    : drv_epd_if.c
***********************************************************/
#include "drv_epd_if.h"
#include <rtdevice.h>

#define EPD_DELAY(ms)       rt_thread_delay(rt_tick_from_millisecond(ms))

static struct rt_device epd_if;

inline static void drv_epd_if_bus_init(void)
{
    rt_pin_mode(EPD_SCK_PIN, PIN_MODE_OUTPUT);
    rt_pin_write(EPD_SCK_PIN, PIN_LOW);
    rt_pin_mode(EPD_DAT_PIN, PIN_MODE_OUTPUT);
    rt_pin_write(EPD_DAT_PIN, PIN_HIGH);
}

static void drv_epd_if_bus_write(uint8_t data)
{
    rt_pin_write(EPD_CS_PIN, PIN_LOW);
    for(int i=0; i<8; i++) {
        if(data&0x80) {
            rt_pin_write(EPD_DAT_PIN, PIN_HIGH);
        } else {
            rt_pin_write(EPD_DAT_PIN, PIN_LOW);
        }
        rt_pin_write(EPD_SCK_PIN, PIN_HIGH);
        data <<= 1;
        rt_pin_write(EPD_SCK_PIN, PIN_LOW);
    }
    rt_pin_write(EPD_CS_PIN, PIN_HIGH);
}

inline static void drv_epd_if_io_init(void)
{
    rt_pin_mode(EPD_CS_PIN, PIN_MODE_OUTPUT);
    rt_pin_write(EPD_CS_PIN, PIN_HIGH);
    rt_pin_mode(EPD_DC_PIN, PIN_MODE_OUTPUT);
    rt_pin_write(EPD_DC_PIN, PIN_HIGH);
    rt_pin_mode(EPD_RST_PIN, PIN_MODE_OUTPUT);
    rt_pin_write(EPD_RST_PIN, PIN_HIGH);
    rt_pin_mode(EPD_BUSY_PIN, PIN_MODE_INPUT);
}

inline static void drv_epd_if_reset(void)
{
    rt_pin_write(EPD_RST_PIN, PIN_LOW);
    EPD_DELAY(200);
    rt_pin_write(EPD_RST_PIN, PIN_HIGH);
    EPD_DELAY(200);
}

inline static void drv_epd_if_wait_until_idle(void)
{
    while(rt_pin_read(EPD_BUSY_PIN) == PIN_HIGH) {
        EPD_DELAY(100);
    }
}

inline static void drv_epd_if_send_data(uint8_t data)
{
    rt_pin_write(EPD_DC_PIN, PIN_HIGH);
    drv_epd_if_bus_write(data);
}

inline static void drv_epd_if_send_command(uint8_t cmd)
{
    rt_pin_write(EPD_DC_PIN, PIN_LOW);
    drv_epd_if_bus_write(cmd);
}

// epdif ops
static rt_err_t drv_epd_if_ops_init(rt_device_t dev)
{
    drv_epd_if_io_init();
    drv_epd_if_bus_init();

    return RT_EOK;
}

static rt_err_t  drv_epd_if_ops_control(rt_device_t dev, int cmd, void *args)
{
    switch(cmd) {
    case EPD_IF_CMD_RESET:
        drv_epd_if_reset();
        break;
    case EPD_IF_CMD_SEND_DATA:
        drv_epd_if_send_data(*(uint8_t *)args);
        break;
    case EPD_IF_CMD_SEND_COMMAND:
        drv_epd_if_send_command(*(uint8_t *)args);
        break;
    case EPD_IF_CMD_WAIT_UNTIL_IDLE:
        drv_epd_if_wait_until_idle();
        break;
    }
    return RT_EOK;
}

#ifdef RT_USING_DEVICE_OPS
static const struct rt_device_ops drv_epd_if_ops = {
    .init = drv_epd_if_ops_init,
    .open = RT_NULL,
    .close = RT_NULL,
    .read = RT_NULL,
    .write = RT_NULL,
    .control = drv_epd_if_ops_control,
};
#endif

int drv_epd_if_init()
{
    rt_memset(&epd_if, 0, sizeof(epd_if));
#ifdef RT_USING_DEVICE_OPS
    epd_if.ops = &drv_epd_if_ops;
#else
    /* common device interface */
    epd_if.init = drv_epd_if_ops_init;
    epd_if.control = drv_epd_if_ops_control;
#endif
    if(rt_device_register(&epd_if, "epdif", RT_DEVICE_FLAG_WRONLY) != RT_EOK) {
        return -1;
    }
    return 0;
}
INIT_BOARD_EXPORT(drv_epd_if_init);

